package com.simple.crawler.core;

import com.simple.crawler.CrawlerEngine;
import com.simple.crawler.aop.AopHelper;
import com.simple.crawler.constant.ExceptionCode;
import com.simple.crawler.exception.CrawlerRuntimeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
@Lazy(false)
public class CrawlerContext implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent> {

    private final static Logger logger = LoggerFactory.getLogger(CrawlerContext.class);

    private static ApplicationContext applicationContext;

    @Autowired
    private CrawlerInitialize crawlerInitialize;

    private static ConcurrentHashMap<String, Crawler> crawlerMap = new ConcurrentHashMap<>();

    //公共缓存区域
    private static ConcurrentHashMap<Object, Object> commonCache = new ConcurrentHashMap<>();

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        applicationContext = context;
    }

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        logger.info("--------------------》初始化爬虫引擎开始《--------------------");
        try {
            if (crawlerInitialize != null) {
                crawlerInitialize.doBefore();
            }
            CrawlerContext.registerObj(AopHelper.getAopHelper().initObj(CrawlerEngine.class));
            if (crawlerInitialize != null) {
                crawlerInitialize.doAfter();
            }
        } catch (Exception e) {
            logger.error("--------------------》初始化爬虫引擎失败《--------------------");
            throw new RuntimeException(e);
        }
        logger.info("--------------------》初始化爬虫引擎完毕《--------------------");
    }

    public static void addCrawler(Crawler crawler) {
        crawlerMap.put(crawler.getId(), crawler);
    }

    public static Map<String, Crawler> getCrawler() {
        return crawlerMap;
    }

    public static Crawler getCrawler(String id) {
        return crawlerMap.get(id);
    }

    public static void addToCache(Object key, Object value) {
        commonCache.put(key, value);
    }

    public static ConcurrentHashMap<Object, Object> getAllCache() {
        return commonCache;
    }

    public static <T> T getValueFromCache(Object key, Class<T> c) {
        return getValueFromCache(key, c, false);
    }

    public static <T> T getValueFromCache(Object key, Class<T> c, boolean deleteFlag) {
        T value = (T) commonCache.get(key);
        if (deleteFlag) {
            commonCache.remove(key);
        }
        return value;
    }

    public static <T> T getObj(Class<T> c) {
        if (applicationContext == null) {
            throw new CrawlerRuntimeException(ExceptionCode.SPRING_NOT_INIT_COMPLETE);
        }
        return applicationContext.getBean(c);
    }

    public static Object registerObj(Object obj) {
        return registerObj(obj.getClass().getName(), obj);
    }
    /**
     * 动态注册bean到Spring中
     * @param name
     * @param obj
     */
    public static Object registerObj(String name, Object obj) {
        if (logger.isDebugEnabled()) {
            logger.debug("动态注册bean：【name:{},obj:{}】", name, obj);
        }
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory)applicationContext.getAutowireCapableBeanFactory();
        if (beanFactory == null) {
            throw new CrawlerRuntimeException(ExceptionCode.SPRING_NOT_INIT_COMPLETE);
        }
        beanFactory.registerSingleton(name, obj);
        return obj;
    }

}
